import os
import argparse
from datetime import datetime
from flask import Flask, request, Response
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

# 全局变量
USERNAME = None

# 配置项
DATA_DIR = "./data"
MAX_HEIGHT = 500  # 最大高度（像素）
os.makedirs(DATA_DIR, exist_ok=True)

def pre_stored_password(app_name, username):
    home_dir = os.path.expanduser('~')
    pwd_file = f"{home_dir}/{app_name}-{username}.pass"
    with open(pwd_file, 'r') as f:
        code = f.read().strip()
        # print(code)
        return code

@auth.verify_password
def verify_password(username, password):
    return username == USERNAME and password == pre_stored_password('memo', username)

def timestamp():
    return datetime.now().strftime("%Y%m%dT%H%M%S")

def list_notes():
    notes = []
    for f in os.listdir(DATA_DIR):
        if f.endswith(".txt"):
            try:
                with open(os.path.join(DATA_DIR, f), 'r', encoding='utf-8') as fd:
                    content = fd.read()
                    ts = datetime.strptime(f[:-4], "%Y%m%dT%H%M%S")
                    notes.append({
                        "id": f[:-4],
                        "time": ts.strftime("%Y-%m-%d %H:%M"),
                        "preview": content[:30].replace('\n', ' ').strip()
                    })
            except:
                continue
    return sorted(notes, key=lambda x: x["id"], reverse=True)

def base_html(content):
    return f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>简易备忘录</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .note-list {{ max-width: 800px; margin: 20px auto; }}
        .note-item {{ 
            padding: 15px; 
            border-bottom: 1px solid #eee;
            transition: background 0.2s;
        }}
        #content-area {{
            min-height: 300px;
            max-height: {MAX_HEIGHT}px;
            overflow-y: auto;
        }}
    </style>
    <script>
        function autoResize(textarea) {{
            textarea.style.height = 'auto';
            let newHeight = Math.min(textarea.scrollHeight, {MAX_HEIGHT});
            textarea.style.height = newHeight + 'px';
        }}
        function makeEditable() {{
            const textarea = document.getElementById('content-area');
            textarea.removeAttribute('readonly');
            textarea.focus();
            event.target.style.display = 'none';
        }}
    </script>
</head>
<body class="bg-light">
    <nav class="navbar navbar-dark bg-primary">
        <div class="container">
            <a class="navbar-brand" href="/">备忘录</a>
            <a href="/new" class="btn btn-light">新建</a>
        </div>
    </nav>
    <div class="container note-list">
        {content}
    </div>
</body>
</html>"""

def note_list():
    notes = list_notes()
    if not notes:
        return base_html('<div class="alert alert-info mt-3">暂无备忘录</div>')
    
    items = []
    for note in notes:
        items.append(f"""
        <div class="note-item bg-white rounded shadow-sm mb-2">
            <div class="d-flex justify-content-between align-items-center">
                <div>
                    <small class="text-muted">{note["time"]}</small>
                    <div class="mt-1">{note["preview"]}</div>
                </div>
                <div>
                    <a href="/view/{note["id"]}" class="btn btn-sm btn-outline-primary">查看</a>
                    <a href="/delete/{note["id"]}" 
                       class="btn btn-sm btn-outline-danger"
                       onclick="return confirm('确认删除？')">删除</a>
                </div>
            </div>
        </div>""")
    
    return base_html('\n'.join(items))

def viewer(note_id, content=""):
    return base_html(f"""
        <div style="padding-bottom: 3px;">
            <a class="btn btn-primary" href="/edit/{note_id}">启用编辑</a>
        </div>
        <textarea 
            id="content-area"
            class="form-control mb-3" 
            name="content" 
            placeholder="输入内容..."
            oninput="autoResize(this)"
            style="height: 100%;"
            readonly="readonly"
            >{content}</textarea>
        <div>
            <a class="btn btn-primary" href="/edit/{note_id}">启用编辑</a>
        </div>
    """)

def editor(content=""):
    return base_html(f"""
    <form method="post" class="bg-white p-4 rounded shadow-sm">
        <div class="d-flex justify-content-end gap-2">
            <button type="submit" class="btn btn-primary">保存</button>
            <a href="/" class="btn btn-outline-secondary">取消</a>
        </div>
        <textarea 
            id="content-area"
            class="form-control mb-3" 
            name="content" 
            placeholder="输入内容..."
            oninput="autoResize(this)"
            style="height: 100px"
            >{content}</textarea>
    </form>
    """)

@app.route('/')
@auth.login_required
def index():
    return note_list()

@app.route('/new', methods=['GET', 'POST'])
@auth.login_required
def new():
    if request.method == 'POST':
        note_id = timestamp()
        content = request.form["content"]
        with open(os.path.join(DATA_DIR, f"{note_id}.txt"), 'w', encoding='utf-8') as f:
            f.write(content)
        return Response(note_list(), headers={'Location': '/'}, status=303)
    return editor()

@app.route('/view/<note_id>', methods=['GET'])
@auth.login_required
def view(note_id):
    path = os.path.join(DATA_DIR, f"{note_id}.txt")
    try:
        with open(path, 'r', encoding='utf-8') as f:
            content = f.read()
        return viewer(note_id, content)
    except Exception as e:
        print(e)
        return Response(note_list(), headers={'Location': '/'}, status=303)

@app.route('/edit/<note_id>', methods=['GET', 'POST'])
@auth.login_required
def edit(note_id):
    path = os.path.join(DATA_DIR, f"{note_id}.txt")
    
    if request.method == 'POST':
        content = request.form["content"]
        with open(path, 'w', encoding='utf-8') as f:
            f.write(content)
        return Response(note_list(), headers={'Location': '/'}, status=303)
    
    try:
        with open(path, 'r', encoding='utf-8') as f:
            content = f.read()
        return editor(content)
    except:
        return Response(note_list(), headers={'Location': '/'}, status=303)

@app.route('/delete/<note_id>')
@auth.login_required
def delete(note_id):
    path = os.path.join(DATA_DIR, f"{note_id}.txt")
    if os.path.exists(path):
        os.remove(path)
    return Response(note_list(), headers={'Location': '/'}, status=303)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-p', '--port', type=int, default=8086, help='Port number to run the server on')
    parser.add_argument('-u', '--user', default="user", help='Username for authentication')
    args = parser.parse_args()

    USERNAME = args.user
    app.run(host='0.0.0.0', port=args.port, debug=True)

